import React, {
  Component,
  createContext,
  CSSProperties,
  FC,
  useCallback,
  useContext,
  useEffect,
  useRef,
} from 'react';

export const ScopeContext = createContext<any>({});

export interface AliveScopeTypeProps {
  className?: string;
  id?: string;
  style?: CSSProperties;
}
interface AliveScopeTypeState {}
// 作用域
export class AliveScope extends Component<
  AliveScopeTypeProps,
  AliveScopeTypeState
> {
  private nodes: {};
  constructor(props: AliveScopeTypeProps | Readonly<AliveScopeTypeProps>) {
    super(props);
    this.nodes = {};
    this.state = {};
  }

  keep = (id: string, children: any) => {
    return new Promise(resolve =>
      this.setState(
        {
          [id]: { id, children },
        },
        () => {
          debugger;
          resolve(this.nodes[id]);
        },
      ),
    );
  };
  render() {
    return (
      <ScopeContext.Provider value={this.keep}>
        {this.props.children}
        {Object.values(this.state).map(({ id, children }: any) => (
          <div
            key={id}
            ref={node => {
              debugger;
              this.nodes[id] = node;
            }}
          >
            {children}
          </div>
        ))}
      </ScopeContext.Provider>
    );
  }
}

export interface KeepAliveTypeProps {
  className?: string;
  id?: string;
  style?: CSSProperties;
}
// keepAlive
const KeepAlive: FC<KeepAliveTypeProps> = props => {
  const keep = useContext(ScopeContext);
  const placeholderRef = useRef<any>(document.createElement('div'));

  const init = useCallback(async () => {
    const realContent = await keep(props.id, props.children);
    debugger;
    placeholderRef.current.appendChild(realContent);
  }, []);

  // init
  useEffect(() => {
    init();
  }, [init]);

  return <div ref={placeholderRef} />;
};

type KeepAliveComponentType = FC<KeepAliveTypeProps> & {
  AliveScope?: any;
};
let KeepAliveComponent: KeepAliveComponentType = React.memo(KeepAlive);
KeepAliveComponent.AliveScope = AliveScope;
export default KeepAliveComponent;
